package com.yumingjaing.utils;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * HttpClient工具类
 * <p>
 * 提供同步和异步的HTTP请求方法，支持GET、POST、PUT、DELETE，以及自定义header和超时时间。
 * </p>
 *
 * @author yumingjing
 * @date 2021/12/28 15:03
 */
public final class HttpClientUtil {

    /**
     * 默认连接池大小
     */
    private static final int DEFAULT_CONNECTION_POOL_SIZE = 200;

    /**
     * 默认连接超时时间
     */
    private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(5);

    /**
     * HttpClient 实例，使用static final确保全局唯一，并使用Builder构建，推荐使用这种方式
     */
    private static final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(DEFAULT_CONNECT_TIMEOUT)
            .build();

    /**
     * 私有构造方法，防止实例化
     */
    private HttpClientUtil() {
        // 防止实例化
    }

    /**
     * 构建HttpRequest，支持设置header
     *
     * @param uri     请求地址
     * @param method  请求方法 (GET/POST/...)
     * @param body    请求体，可以为null
     * @param headers 请求头，可以为null
     * @param timeout 超时时间，可以为null，如果为null则使用默认超时时间
     * @return HttpRequest
     */
    private static HttpRequest buildRequest(String uri, String method, String body, Map<String, String> headers, Duration timeout) {
        HttpRequest.Builder builder = HttpRequest.newBuilder()
                .uri(URI.create(uri))
                .method(method, body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(body));

        if (timeout != null) {
            builder.timeout(timeout);
        }

        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.header(entry.getKey(), entry.getValue());
            }
        }
        return builder.build();
    }

    /**
     * 发送GET请求
     *
     * @param uri 请求地址
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> get(String uri) throws IOException, InterruptedException {
        return get(uri, null, null);
    }

    /**
     * 发送GET请求
     *
     * @param uri     请求地址
     * @param headers 请求头
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> get(String uri, Map<String, String> headers) throws IOException, InterruptedException {
        return get(uri, headers, null);
    }

    /**
     * 发送GET请求
     *
     * @param uri     请求地址
     * @param timeout 请求超时时间
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> get(String uri, Duration timeout) throws IOException, InterruptedException {
        return get(uri, null, timeout);
    }

    /**
     * 发送带header的GET请求
     *
     * @param uri     请求地址
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return HttpResponse<String>
     * @throws IOException          IO异常
     * @throws InterruptedException 中断异常
     */
    public static HttpResponse<String> get(String uri, Map<String, String> headers, Duration timeout) throws IOException, InterruptedException {
        HttpRequest request = buildRequest(uri, "GET", null, headers, timeout);
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 发送POST请求
     *
     * @param uri  请求地址
     * @param body 请求体
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> post(String uri, String body) throws IOException, InterruptedException {
        return post(uri, body, null, null);
    }

    /**
     * 发送POST请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> post(String uri, String body, Map<String, String> headers) throws IOException, InterruptedException {
        return post(uri, body, headers, null);
    }

    /**
     * 发送POST请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param timeout 请求超时时间
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> post(String uri, String body, Duration timeout) throws IOException, InterruptedException {
        return post(uri, body, null, timeout);
    }

    /**
     * 发送带header的POST请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return HttpResponse<String>
     * @throws IOException          IO异常
     * @throws InterruptedException 中断异常
     */
    public static HttpResponse<String> post(String uri, String body, Map<String, String> headers, Duration timeout) throws IOException, InterruptedException {
        HttpRequest request = buildRequest(uri, "POST", body, headers, timeout);
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 发送PUT请求
     *
     * @param uri  请求地址
     * @param body 请求体
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> put(String uri, String body) throws IOException, InterruptedException {
        return put(uri, body, null, null);
    }

    /**
     * 发送PUT请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> put(String uri, String body, Map<String, String> headers) throws IOException, InterruptedException {
        return put(uri, body, headers, null);
    }

    /**
     * 发送PUT请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param timeout 请求超时时间
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> put(String uri, String body, Duration timeout) throws IOException, InterruptedException {
        return put(uri, body, null, timeout);
    }

    /**
     * 发送带header的PUT请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return HttpResponse<String>
     * @throws IOException          IO异常
     * @throws InterruptedException 中断异常
     */
    public static HttpResponse<String> put(String uri, String body, Map<String, String> headers, Duration timeout) throws IOException, InterruptedException {
        HttpRequest request = buildRequest(uri, "PUT", body, headers, timeout);
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 发送DELETE请求
     *
     * @param uri 请求地址
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> delete(String uri) throws IOException, InterruptedException {
        return delete(uri, null, null);
    }

    /**
     * 发送DELETE请求
     *
     * @param uri     请求地址
     * @param headers 请求头
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> delete(String uri, Map<String, String> headers) throws IOException, InterruptedException {
        return delete(uri, headers, null);
    }

    /**
     * 发送DELETE请求
     *
     * @param uri     请求地址
     * @param timeout 请求超时时间
     * @return HttpResponse
     * @throws IOException
     * @throws InterruptedException
     */
    public static HttpResponse<String> delete(String uri, Duration timeout) throws IOException, InterruptedException {
        return delete(uri, null, timeout);
    }

    /**
     * 发送带header的DELETE请求
     *
     * @param uri     请求地址
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return HttpResponse<String>
     * @throws IOException          IO异常
     * @throws InterruptedException 中断异常
     */
    public static HttpResponse<String> delete(String uri, Map<String, String> headers, Duration timeout) throws IOException, InterruptedException {
        HttpRequest request = buildRequest(uri, "DELETE", null, headers, timeout);
        return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    // ---------------------- 异步方法 ----------------------

    /**
     * 异步发送GET请求
     *
     * @param uri     请求地址
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return CompletableFuture<HttpResponse < String>>
     */
    public static CompletableFuture<HttpResponse<String>> getAsync(String uri, Map<String, String> headers, Duration timeout) {
        HttpRequest request = buildRequest(uri, "GET", null, headers, timeout);
        return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 异步发送POST请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return CompletableFuture<HttpResponse < String>>
     */
    public static CompletableFuture<HttpResponse<String>> postAsync(String uri, String body, Map<String, String> headers, Duration timeout) {
        HttpRequest request = buildRequest(uri, "POST", body, headers, timeout);
        return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 异步发送PUT请求
     *
     * @param uri     请求地址
     * @param body    请求体
     * @param headers 请求头
     * @param timeout 请求超时时间
     * @return CompletableFuture<HttpResponse < String>>
     */
    public static CompletableFuture<HttpResponse<String>> putAsync(String uri, String body, Map<String, String> headers, Duration timeout) {
        HttpRequest request = buildRequest(uri, "PUT", body, headers, timeout);
        return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }

    /**
     * 异步发送DELETE请求
     * @param uri
     * @param headers
     * @param timeout
     * @return
     */
    public static CompletableFuture<HttpResponse<String>> deleteAsync(String uri, Map<String, String> headers, Duration timeout) {
        HttpRequest request = buildRequest(uri, "DELETE", null, headers, timeout);
        return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }
    //可以考虑支持其他方法。
}
